package com.ak.game.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.ak.game.entity.PnGame;
import com.ak.game.entity.PnTally;
import com.ak.game.entity.PnUserStream;
import com.ak.game.entity.PnVipUser;
import com.ak.game.exception.ServiceException;
import com.ak.game.mapper.PnUserStreamMapper;
import com.ak.game.mapper.PnVipUserMapper;
import com.ak.game.service.PnGameService;
import com.ak.game.service.PnTallyService;
import com.ak.game.service.PnUserStreamService;
import com.ak.game.util.CommonUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

/**
 * vip用户游戏记录表(PnUserStream)表服务实现类
 *
 * @author makejava
 * @since 2024-05-17 19:45:49
 */
@Slf4j
@Service
public class PnUserStreamServiceImpl extends ServiceImpl<PnUserStreamMapper, PnUserStream> implements PnUserStreamService {

    @Autowired
    private PnTallyService tallyService;

    @Autowired
    private PnVipUserMapper vipUserMapper;

    @Autowired
    private PnGameService gameService;

    /**
     * 用户下注
     *
     * @return
     */
    @Override
    @Transactional
    public boolean saveUserBetting(Integer tallyType, Object data, Object game) {
        HashMap dataMap = (HashMap) data;
        HashMap gameMap = (HashMap) game;
        try {
            if (ObjectUtil.isNull(dataMap) || ObjectUtil.isNull(gameMap.get("start_time")) || ObjectUtil.isNull(gameMap.get("round_id")))
                throw new ServiceException("10005");
            // 异步验证游戏信息
            CompletableFuture<PnGame> gameFuture = CommonUtil.fetchAndVerifyEntity(
                    gameMap.get("id").toString(),
                    gameService::getById,
                    "10000"
            );
            // 异步验证用户信息
            CompletableFuture<PnVipUser> vipUserFuture = CommonUtil.fetchAndVerifyEntity(
                    dataMap.get("user_id") + "",
                    vipUserMapper::selectByIdForUpdate,
                    "10001"
            );


            CompletableFuture.allOf(gameFuture, vipUserFuture).join();
            PnGame pnGame = gameFuture.get();
            PnVipUser vipUser = vipUserFuture.get();
            BigDecimal userMoney = vipUser.getMoney();
            // 获取下注金额
            if (ObjectUtil.isNull(dataMap.get("amount")) || new BigDecimal(dataMap.get("amount").toString()).compareTo(BigDecimal.ZERO) == 0)
                throw new ServiceException("10005");
            BigDecimal amount = new BigDecimal(dataMap.get("amount") + "");
            if (amount.compareTo(BigDecimal.ZERO) == 0) throw new ServiceException("10005");
            // 判断用户余额够不够
            if (amount.compareTo(userMoney) > 0) {
                log.error("用户钱包余额不足");
                throw new ServiceException("10002");
            }
            BigDecimal nowBalance = userMoney.subtract(amount);
            vipUserMapper.updateMoneyById(dataMap.get("user_id").toString(), nowBalance);
            // 存入pn_tally表
            PnTally pnTally = new PnTally();
            pnTally.setBinding(vipUser.getBinding());
            pnTally.setUsername(vipUser.getUsername());
            pnTally.setTallyType(tallyType);
            pnTally.setTransfer(amount.abs());
            pnTally.setLastBalance(userMoney);
            pnTally.setNowBalance(nowBalance);
            pnTally.setCreateTime(new Date());
            pnTally.setOperator(vipUser.getBinding());
            pnTally.setDitch(pnGame.getVassalage());
            pnTally.setSuperior(vipUser.getSuperior());
            pnTally.setAffiliation(vipUser.getAffiliation());
            pnTally.setChief(vipUser.getChief());
            pnTally.setCurrency(vipUser.getCurrency());
            tallyService.save(pnTally);
            // 存入pn_user_stream表
            PnUserStream pnUserStream = new PnUserStream();
            if (ObjectUtil.isEmpty(dataMap.get("type"))) {
                pnUserStream.setPlaysessionId(gameMap.get("id").toString() + gameMap.get("round_id").toString() + vipUser.getBinding());
            } else {
                pnUserStream.setPlaysessionId(gameMap.get("id").toString() + gameMap.get("round_id").toString() + vipUser.getBinding() + dataMap.get("type").toString());
            }
            pnUserStream.setExternalPlayerId(vipUser.getBinding());
            pnUserStream.setGameId(pnGame.getGameCode());
            pnUserStream.setStartDate(CommonUtil.formatLong2Date(gameMap.get("start_time")));
            pnUserStream.setEndDate(CommonUtil.formatLong2Date(gameMap.get("start_time")));
            pnUserStream.setStartTime(CommonUtil.formatLong2Date(gameMap.get("start_time")));
            pnUserStream.setEndTime(CommonUtil.formatLong2Date(gameMap.get("start_time")));
            pnUserStream.setBet(new BigDecimal(dataMap.get("amount").toString()));
            pnUserStream.setWin(BigDecimal.ZERO);
            pnUserStream.setCurrency(vipUser.getCurrency());
            pnUserStream.setVassalage(pnGame.getVassalage());
            pnUserStream.setCreateTime(new Date());
            pnUserStream.setItemStr(JSON.toJSONString(Map.of("data", data, "game", game)));
            pnUserStream.setTimestampTime(System.currentTimeMillis());
            pnUserStream.setGameStartTime(Long.parseLong(gameMap.get("start_time").toString()));
            save(pnUserStream);
            return true;
        } catch (Exception e) {
            if (e instanceof DuplicateKeyException) throw new ServiceException("10003");
            if (e instanceof CompletionException) throw new ServiceException(e.getCause().getMessage());
            log.error("用户下注记录保存失败，请求参数：data={}，game={}，原因={}", dataMap, gameMap, e.getMessage());
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 保存单个用户下注结果
     *
     * @param data
     * @param game
     */
    @Transactional
    @Override
    public void saveUserResultRecord(Integer tallyType, Object data, Object game) {
        HashMap dataMap = (HashMap) data;
        HashMap gameMap = (HashMap) game;
        // 获取游戏表的数据
        PnGame pnGame = gameService.getById(gameMap.get("id").toString());
        // 获取用户表的数据
        PnVipUser vipUser = vipUserMapper.selectByIdForUpdate(dataMap.get("user_id").toString());
        if (ObjectUtil.isNull(pnGame)) {
            log.error("pn_game表游戏信息无数据，请求参数：id={}", gameMap.get("id").toString());
            throw new ServiceException("10000");
        }
        if (ObjectUtil.isNull(vipUser)) {
            log.error("pn_vip_user表游戏信息无数据，请求参数：id={}", dataMap.get("user_id").toString());
            throw new ServiceException("10001");
        }
        // 更新pn_user_stream表的数据
        LambdaUpdateWrapper<PnUserStream> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(PnUserStream::getExternalPlayerId, vipUser.getBinding());
        updateWrapper.eq(PnUserStream::getPlaysessionId, gameMap.get("round_id").toString());
        updateWrapper.set(PnUserStream::getWin, new BigDecimal(dataMap.get("amount").toString()));
        updateWrapper.set(PnUserStream::getEndDate, CommonUtil.formatLong2Date(gameMap.get("end_time")));
        updateWrapper.set(PnUserStream::getEndTime, CommonUtil.formatLong2Date(gameMap.get("end_time")));
        update(updateWrapper);
        // 插入pn_tally表的数据
        // 账变金额
        BigDecimal amount = new BigDecimal(dataMap.get("amount").toString());
        BigDecimal nowBalance = vipUser.getMoney().add(amount);
        PnTally pnTally = new PnTally();
        pnTally.setBinding(vipUser.getBinding());
        pnTally.setUsername(vipUser.getUsername());
        pnTally.setTallyType(tallyType);
        pnTally.setTransfer(amount.abs());
        pnTally.setLastBalance(vipUser.getMoney());
        pnTally.setNowBalance(vipUser.getMoney().add(amount));
        pnTally.setCreateTime(new Date());
        pnTally.setOperator(vipUser.getBinding());
        pnTally.setDitch(pnGame.getVassalage());
        pnTally.setSuperior(vipUser.getSuperior());
        pnTally.setAffiliation(vipUser.getAffiliation());
        pnTally.setChief(vipUser.getChief());
        pnTally.setCurrency(vipUser.getCurrency());
        tallyService.save(pnTally);
        // 更新pn_vip_user表的money字段
        vipUserMapper.updateMoneyById(vipUser.getId(), nowBalance);
    }

    @Override
    @Transactional
    public void saveUserStream(List<String> list, String gameId, String roundId, Date endTime, Integer tallyType) {
        for (String item : list) {
            HashMap map = (HashMap) JSON.parse(item);
            // 获取游戏表的数据
            PnGame pnGame = gameService.getById(gameId);
            // 获取用户表的数据
            PnVipUser vipUser = vipUserMapper.selectByIdForUpdate(map.get("user_id").toString());
            if (ObjectUtil.isNull(pnGame)) {
                log.error("pn_game表游戏信息无数据，请求参数：id={}", gameId);
                throw new ServiceException("10000");
            }
            if (ObjectUtil.isNull(vipUser)) {
                log.error("pn_vip_user表游戏信息无数据，请求参数：id={}", map.get("user_id").toString());
                throw new ServiceException("10001");
            }
            // 更新pn_user_stream表的数据
            LambdaUpdateWrapper<PnUserStream> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(PnUserStream::getExternalPlayerId, vipUser.getBinding());
            // 拼接更新的where条件playSession_id字段
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(gameId);
            if (ObjectUtil.isNotEmpty(map.get("round_id"))) {
                stringBuilder.append(map.get("round_id").toString());
            } else {
                stringBuilder.append(roundId);
            }
            stringBuilder.append(vipUser.getBinding());
            if (ObjectUtil.isNotEmpty(map.get("type"))) {
                stringBuilder.append(map.get("type").toString());
            }
            updateWrapper.eq(PnUserStream::getPlaysessionId, stringBuilder);
            updateWrapper.set(PnUserStream::getWin, new BigDecimal(map.get("win").toString()));
            updateWrapper.set(PnUserStream::getEndDate, endTime);
            update(updateWrapper);
            // 插入pn_tally表的数据
            // 账变金额
            if (ObjectUtil.isNull(map.get("win")))
                throw new ServiceException("10005");
            BigDecimal amount = new BigDecimal(map.get("win").toString());
            if (amount.compareTo(BigDecimal.ZERO) != 0) {
                BigDecimal nowBalance = vipUser.getMoney().add(amount);
                PnTally pnTally = new PnTally();
                pnTally.setBinding(vipUser.getBinding());
                pnTally.setUsername(vipUser.getUsername());
                pnTally.setTallyType(tallyType);
                pnTally.setTransfer(amount.abs());
                pnTally.setLastBalance(vipUser.getMoney());
                pnTally.setNowBalance(vipUser.getMoney().add(amount));
                pnTally.setCreateTime(new Date());
                pnTally.setOperator(vipUser.getBinding());
                pnTally.setDitch(pnGame.getVassalage());
                pnTally.setSuperior(vipUser.getSuperior());
                pnTally.setAffiliation(vipUser.getAffiliation());
                pnTally.setChief(vipUser.getChief());
                pnTally.setCurrency(vipUser.getCurrency());
                tallyService.save(pnTally);
                // 更新pn_vip_user表的money字段
                vipUserMapper.updateMoneyById(vipUser.getId(), nowBalance);
            }
        }

    }
}

